﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace TresselLS
{
    public partial class LinkerForm : Form
    {
        public LinkerForm()
        {
            /*!
            Procedure Name: LinkerForm
            Description: the LinkerForm constructor
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            InitializeComponent();
        }
        [STAThread]
        static void Main()
        {
            /*!
            Procedure Name: Main
            Description: the entry point for the application
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new LinkerForm());
        }
        /*#
        Variable Name: displayTimer
        Module Where Defined: LinkerForm
        Data Type: Timer
        Local or Global: Global
        Purpose: used to wait until the open file dialog is closed before further processing
        #*/
        private Timer displayTimer = new Timer();
        private void LinkerFormLoad(object sender, EventArgs e)
        {
            /*!
            Procedure Name: LinkerFormLoad
            Description: initializes variables when the form first loads
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: buttonTip
            Module Where Defined: LinkerFormLoad
            Data Type: ToolTip
            Local or Global: Local
            Purpose: used to display the function of the removeObjectFile button
            #*/
            ToolTip buttonTip = new ToolTip();
            buttonTip.SetToolTip(removeObjectFileButton, "Remove the last Object File in the Queue.");
            openFileDialog.Title = "Object File Location";
            displayTimer.Interval = 200;
            displayTimer.Tick += new EventHandler(displayTimerTick);
        }

        void displayTimerTick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: displayTimerTick
            Description: stops the timer and starts processing the object files
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            displayTimer.Stop();
            /*#
            Variable Name: singleFile
            Module Where Defined: displayTimerTick
            Data Type: string
            Local or Global: Local
            Purpose: holds each file name that the user selects
            #*/
            foreach (string singleFile in openFileDialog.FileNames)
            {
                /*#
                Variable Name: objectFileCol
                Module Where Defined: displayTimerTick
                Data Type: DataGridViewColumn
                Local or Global: Local
                Purpose: holds the first displayed object file
                #*/
                DataGridViewColumn objectFileCol = new DataGridViewColumn();
                objectFileCol.HeaderText = singleFile.Substring(singleFile.LastIndexOf("\\") + 1);
                objectFileCol.ToolTipText = singleFile;
                linkerDataGridView.Columns.Add(objectFileCol);
            }
        }

        private void linkerDataGridViewColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
        {
            /*!
            Procedure Name: linkerDataGridViewColumnDisplayIndexChanged
            Description: maintains the first object file colored blue, indicating it is the main file in the linker
            Input Parameters: object sender, DataGridViewColumnEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            for (int i = 0; i < linkerDataGridView.Columns.Count; i++)
            {
                if (linkerDataGridView.Columns[i].DisplayIndex == 0)
                {
                    linkerDataGridView.Columns[i].HeaderCell.Style.BackColor = Color.LightBlue;
                }
                else
                {
                    linkerDataGridView.Columns[i].HeaderCell.Style.BackColor = SystemColors.Control;
                }
            }
        }

        private void removeObjectFileButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: removeObjectFileButtonClick
            Description: removes the last object file in the list
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            this.linkerDataGridView.Columns.Remove(linkerDataGridView.Columns.GetLastColumn(DataGridViewElementStates.Displayed,DataGridViewElementStates.None));
        }

        private void linkerDataGridViewColumnRemoved(object sender, DataGridViewColumnEventArgs e)
        {
            /*!
            Procedure Name: linkerDataGridViewColumnRemoved
            Description: keeps the display looking beautiful
            Input Parameters: object sender, DataGridViewColumnEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (linkerDataGridView.Columns.Count == 0)
            {
                removeObjectFileButton.Enabled = false;
                linkButton.Visible = false;
            }
        }

        private void browserButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: browserButtonClick
            Description: opens the file dialog
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            openFileDialog.ShowDialog();
        }

        private void openFileDialogFileOk(object sender, CancelEventArgs e)
        {
            /*!
            Procedure Name: openFileDialogFileOk
            Description: starts the timer
            Input Parameters: object sender, CancelEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            displayTimer.Start();
        }

        private void linkerDataGridViewColumnAdded(object sender, DataGridViewColumnEventArgs e)
        {
            /*!
            Procedure Name: linkerDataGridViewColumnAdded
            Description: keeps the display looking beautiful
            Input Parameters: object sender, DataGridViewColumnEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (!removeObjectFileButton.Enabled)
            {
                removeObjectFileButton.Enabled = true;
            }
            if (!linkButton.Visible)
            {
                linkButton.Visible = true;
            }
            if (linkerDataGridView.Columns.Count == 1)
            {
                linkerDataGridView.Columns[0].HeaderCell.Style.BackColor = Color.LightBlue;
            }
        }

        private void linkButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: linkButtonClick
            Description: concatenates the object files and passes the combined string into the Linker
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/25/2009
            Why: check if fatal errors exist and enable/disable buttons as needed
            Who: Steve Rudy
            When: 11/29/2009
            Why: needed to more effectively track fatal errors
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: linkerFile
            Module Where Defined: linkButtonClick
            Data Type: string
            Local or Global: Local
            Purpose: holds the concatenated object files
            #*/
            string linkerFile = "";
            /*#
            Variable Name: columnCount
            Module Where Defined: linkButtonClick
            Data Type: int
            Local or Global: Local
            Purpose: holds the number of object files to be linked
            #*/
            int columnCount = linkerDataGridView.Columns.Count;
            /*#
            Variable Name: outOfMemError
            Module Where Defined: linkButtonClick
            Data Type: bool
            Local or Global: Local
            Purpose: keeps track of if computer is out of memory
            #*/
            bool outOfMemError = false;
            try
            {
                for (int i = 0; i < columnCount; i++)
                {
                    /*#
                    Variable Name: firstColumn
                    Module Where Defined: linkButtonClick
                    Data Type: DataGridViewColumn
                    Local or Global: Local
                    Purpose: holds the first column to be linked
                    #*/
                    DataGridViewColumn firstColumn = linkerDataGridView.Columns.GetFirstColumn(DataGridViewElementStates.None);
                    /*#
                    Variable Name: objectFileReader
                    Module Where Defined: linkButtonClick
                    Data Type: TextReader
                    Local or Global: Local
                    Purpose: reads the text in the current object file
                    #*/
                    TextReader objectFileReader = new StreamReader(firstColumn.ToolTipText);
                    /*#
                    Variable Name: currentFile
                    Module Where Defined: linkButtonClick
                    Data Type: string
                    Local or Global: Local
                    Purpose: holds the current object file
                    #*/
                    string currentFile = objectFileReader.ReadToEnd();
                    if (currentFile.Length > 0)
                    {
                        if (!currentFile.EndsWith(Environment.NewLine) && i != columnCount - 1)
                        {
                            currentFile = currentFile + Environment.NewLine;
                        }
                        linkerFile += currentFile;
                    }
                    linkerDataGridView.Columns.Remove(firstColumn);
                    objectFileReader.Close();
                }
            }
            catch (System.OutOfMemoryException)
            {
                outOfMemError = true;
                MessageBox.Show("Out of memory.  Total object file size cannot exceed total memory.");
            }
            reportDisplayDataGridView.Rows.Clear();
            if (!outOfMemError)
            {
                objectLinker = new TresselLinker(linkerFile);
                objectLinker.Initialize();
                /*#
                Variable Name: isFatal
                Module Where Defined: linkButtonClick
                Data Type: bool
                Local or Global: Local
                Purpose: stores whether a fatal error has been encountered at a specific line
                #*/
                bool isFatal = false;
                for (int i = 0; i < objectLinker.objectSourceArray.Length && !isFatal; i++)
                {
                    this.reportDisplayDataGridView.Rows.Add(objectLinker.objectSourceArray[i].ToString());
                    isFatal = OutputErrors(i);
                }
                if (objectLinker.FatalErrorFlag)
                {
                    viewModuleButton.Enabled = false;
                    simulateButton.Enabled = false;
                }
                else
                {
                    viewModuleButton.Enabled = true;
                    simulateButton.Enabled = true;
                }
            }
        }
        private bool OutputErrors(int lineNum)
        {
            /*!
            Procedure Name: OutputErrors
            Description: outputs all errors for a given line
            Input Parameters: int lineNum
            Output Parameters: bool
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/24/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/29/2009
            Why: need to return whether a fatal error is found or not
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: myRow
            Module Where Defined: OutputErrors
            Data Type: DataRow[]
            Local or Global: Local
            Purpose: holds the resulting rows of the error table search
            #*/
            DataRow[] myRow = objectLinker.ErrorTable.Select("LINE='" + lineNum + "'");
            /*#
            Variable Name: isFatal
            Module Where Defined: OutputErrors
            Data Type: bool
            Local or Global: Local
            Purpose: stores whether a fatal error has been encountered
            #*/
            bool isFatal = false;
            /*#
            Variable Name: row
            Module Where Defined: OutputErrors
            Data Type: DataRow
            Local or Global: Local
            Purpose: holds each result from the error table search
            #*/
            foreach (DataRow row in myRow)
            {
                reportDisplayDataGridView.Rows.Add("   " + row["MESSAGE"].ToString());
                switch (row["TYPE"].ToString().ToUpper())
                {
                    case "WARNING":
                        reportDisplayDataGridView.Rows[reportDisplayDataGridView.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.Blue;
                        break;
                    case "INTERMEDIATE":
                        reportDisplayDataGridView.Rows[reportDisplayDataGridView.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.Orange;
                        break;
                    case "FATAL":
                        reportDisplayDataGridView.Rows[reportDisplayDataGridView.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.Red;
                        isFatal = true;
                        break;
                }
            }
            return isFatal;
        }
        private void simulateButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: simulateButtonClick
            Description: shows the simulator form
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/24/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/29/2009
            Why: the simulator form should be a modal dialog
            Who: Steve Rudy
            When: 11/30/2009
            Why: the simulator shouldn't be remembering register values
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: simulatorDisplay
            Module Where Defined: simulateButtonClick
            Data Type: SimulatorForm
            Local or Global: Local
            Purpose: displays the simulation and acts as the interface for the user
            #*/
            SimulatorForm simulatorDisplay = new SimulatorForm(objectLinker);
            simulatorDisplay.ShowDialog();
            simulatorDisplay.Dispose();
        }
        private void viewModuleButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: viewModuleButtonClick
            Description: shows the tressel linker output
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 11/24/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            LoadModuleForm displayModule = new LoadModuleForm(this.objectLinker);
            displayModule.Show();
        }
    }
}
